// fork from makepad
// actually, I don't understand these code realy
mod arena;
mod geom;
mod iter;

mod mesh;
mod path;

mod filler;
mod linearizer;
mod stroker;
mod tessellator;
mod trapezoidator;

pub use geom::{Point, Rectangle, Vector};
pub use iter::{FractalIterator, FromFractalIterator, IntoFractalIterator};

pub use mesh::{Callbacks, Mesh, Writer};
pub use path::Path;

pub use filler::{FillRule, Filler, Polygon};
pub use linearizer::{CubicSegment, LineSegment, Linearizer, QuadraticSegment};
pub use stroker::{CapKind, JoinKind, Stroker, StrokerOptions};
pub use tessellator::Tessellator;
pub use trapezoidator::{Trapezoid, Trapezoidated, Trapezoidator};

/// A trait for transformations in 2-dimensional Euclidian space.
pub trait Transformation {
	/// Applies `self` to the given `point`.
	fn transform_point(&self, point: Point) -> Point;
	/// Applies `self` to the given `vector`.
	fn transform_vector(&self, vector: Vector) -> Vector;
}
/// A trait to transform geometric objects in 2-dimensional Euclidian space.
pub trait Transform {
	fn transform(self, t: &impl Transformation) -> Self;
	fn transform_mut(&mut self, t: &impl Transformation);
}

/// A command in a line path
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LineCommand {
	MoveTo(Point),
	LineTo(Point),
	Close,
}
impl Transform for LineCommand {
	fn transform(self, t: &impl Transformation) -> Self {
		match self {
			LineCommand::MoveTo(p) => LineCommand::MoveTo(p.transform(t)),
			LineCommand::LineTo(p) => LineCommand::LineTo(p.transform(t)),
			LineCommand::Close => LineCommand::Close,
		}
	}
	fn transform_mut(&mut self, t: &impl Transformation) {
		*self = self.transform(t);
	}
}
/// An extension trait for iterators over line path commands.
pub trait LineIterator: iter::FractalIterator<Item = LineCommand> {
	fn trapezoidate(self, trapezoidator: &mut Trapezoidator) -> Option<Trapezoidated>
	where
		Self: Sized,
	{
		trapezoidator.reset().trapezoidate(self)
	}
	fn fill(self, fill_rull: FillRule, filler: &mut Filler, callbacks: &mut impl Callbacks)
	where
		Self: Sized,
	{
		filler.reset().fill_iter(self, fill_rull, callbacks)
	}
}
impl<I> LineIterator for I where I: iter::FractalIterator<Item = LineCommand> {}

/// A command in a path
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PathCommand {
	MoveTo(Point),
	LineTo(Point),
	QuadraticTo(Point, Point),
	CubicTo(Point, Point, Point),
	Close,
}
impl Transform for PathCommand {
	fn transform(self, t: &impl Transformation) -> Self {
		match self {
			PathCommand::MoveTo(p) => PathCommand::MoveTo(p.transform(t)),
			PathCommand::LineTo(p) => PathCommand::LineTo(p.transform(t)),
			PathCommand::QuadraticTo(p1, p) => PathCommand::QuadraticTo(p1.transform(t), p.transform(t)),
			PathCommand::CubicTo(p1, p2, p) => PathCommand::CubicTo(p1.transform(t), p2.transform(t), p.transform(t)),
			PathCommand::Close => PathCommand::Close,
		}
	}
	fn transform_mut(&mut self, t: &impl Transformation) {
		*self = self.transform(t);
	}
}

/// An extension trait for iterators over path commands.
pub trait PathIterator: iter::FractalIterator<Item = PathCommand> {
	/// Returns an iterator over line path commands that approximate `self` with tolerance
	/// `epsilon`.
	fn linearize(self, epsilon: f32) -> Linearizer<Self>
	where
		Self: Sized,
	{
		Linearizer::new(self, epsilon)
	}
	fn trapezoidate(self, epsilon: f32, trapezoidator: &mut Trapezoidator, callbacks: &mut impl Callbacks)
	where
		Self: Sized,
	{
		trapezoidator.reset().trapezoidate(self.linearize(epsilon)).map(|trapezoidated| {
			trapezoidated.for_each(&mut |trapezoid| {
				let p0 = callbacks.vertex(trapezoid.xs[0], trapezoid.ys[2]);
				let p1 = callbacks.vertex(trapezoid.xs[1], trapezoid.ys[3]);
				let p2 = callbacks.vertex(trapezoid.xs[1], trapezoid.ys[1]);
				let p3 = callbacks.vertex(trapezoid.xs[0], trapezoid.ys[0]);
				callbacks.triangle(p0, p2, p1);
				callbacks.triangle(p0, p3, p2);
				true
			});
		});
	}
	fn fill(self, epsilon: f32, fill_rull: FillRule, filler: &mut Filler, callbacks: &mut impl Callbacks)
	where
		Self: Sized,
	{
		filler.reset().fill_iter(self.linearize(epsilon), fill_rull, callbacks)
	}
}
impl<I> PathIterator for I where I: iter::FractalIterator<Item = PathCommand> {}
